package cn.blu10ph.trustshare.service.impl;

import cn.blu10ph.trustshare.bean.msg.BaseMsg;
import cn.blu10ph.trustshare.bean.msg.TrustMsg;
import cn.blu10ph.trustshare.bean.node.TrustNode;
import cn.blu10ph.trustshare.bean.notice.GetNoticesMsg;
import cn.blu10ph.trustshare.bean.notice.NoticesMsg;
import cn.blu10ph.trustshare.bean.notice.TrustNotice;
import cn.blu10ph.trustshare.constant.Constant;
import cn.blu10ph.trustshare.service.DHTMsgService;
import cn.blu10ph.trustshare.util.ConvertUtil;
import cn.blu10ph.trustshare.util.HashAndSignUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * <p> DHTGetNoticesMsgServiceImpl </p >
 *
 * @author cxx
 * @date 2024/4/6 22:22
 */
@Slf4j
@Component
public class DHTGetNoticesMsgServiceImpl extends DHTMsgBaseService<GetNoticesMsg> implements DHTMsgService<GetNoticesMsg> {

    @Override
    public void sendReturn(ChannelHandlerContext ctx, DatagramPacket packet, TrustNode node, TrustMsg msg) {
        GetNoticesMsg getNoticesMsg;
        try {
            if(StringUtils.hasText(msg.getParams())) {
                getNoticesMsg = ConvertUtil.str2Obj(msg.getParams(), GetNoticesMsg.class);
            } else {
                getNoticesMsg = new GetNoticesMsg();
            }
        } catch (JsonProcessingException ex) {
            ex.printStackTrace();
            return;
        }
        if(!StringUtils.hasText(getNoticesMsg.getBaseHash()) && !StringUtils.hasText(getNoticesMsg.getFromNode())){
            // if get root notice, return self notice.
            getNoticesMsg.setBaseHash("");
            getNoticesMsg.setFromNode(routingTable.getNodeId());
        }
        List<TrustNotice> notices = noticeService.findMsg(getNoticesMsg);

        BaseMsg msgObj = getBaseMsg(Constant.MSG_DIRECTION_RETURN, node.getNodeId());
        NoticesMsg noticesMsg = new NoticesMsg(getNoticesMsg);
        noticesMsg.setNotices(notices);
        try {
            msgObj.setParams(ConvertUtil.obj2Str(noticesMsg));
            response(node, ctx, packet.sender(), msgObj);
        } catch (JsonProcessingException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void receive(ChannelHandlerContext ctx, DatagramPacket packet, TrustNode node, TrustMsg msg) {
        NoticesMsg noticesMsg;
        try {
            noticesMsg = ConvertUtil.str2Obj(msg.getParams(), NoticesMsg.class);
        } catch (JsonProcessingException ex) {
            ex.printStackTrace();
            return;
        }
        List<TrustNotice> notices = noticesMsg.getNotices();
        notices.forEach(notice->{
            // notice sign check
            if(HashAndSignUtil.checkNoticeHash(notice)){
                PGPPublicKey publicKey = pgpManager.getPublicKey(notice.getFromNode());
                // notice infoHash check
                if(HashAndSignUtil.checkNoticeSign(notice, publicKey)){
                    noticeService.addAll(notices);
                }
            }
        });
    }

    @Override
    protected Class<GetNoticesMsg> getParamsType() {
        return GetNoticesMsg.class;
    }

    @Override
    public String getType() {
        return Constant.MSG_TYPE_GET_NOTICES;
    }

}
